/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "work_sched_utils.h"
#include "work_sched_constants.h"

#include "errors.h"
#include "ohos_account_kits.h"
#include "os_account_manager.h"
#include "tokenid_kit.h"
#include "ipc_skeleton.h"
#include "work_sched_hilog.h"
#include "parameters.h"
#include <if_system_ability_manager.h>
#include <iservice_registry.h>
#include <system_ability_definition.h>
#include "bundle_mgr_proxy.h"

using namespace std;
using namespace OHOS::AppExecFwk;

namespace OHOS {
namespace WorkScheduler {
const int32_t INVALID_DATA = -1;

#ifdef WORK_SCHEDULER_TEST
#define WEAK_FUNC __attribute__((weak))
#else
#define WEAK_FUNC
#endif

int32_t WorkSchedUtils::GetCurrentAccountId()
{
    std::vector<int32_t> osAccountIds;
    ErrCode ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(osAccountIds);
    if (ret != ERR_OK) {
        WS_HILOGE("QueryActiveOsAccountIds failed.");
        return -1;
    }

    if (osAccountIds.empty()) {
        WS_HILOGE("osAccountInfos is empty, no accounts.");
        return -1;
    }

    auto iter = std::find_if(osAccountIds.cbegin(), osAccountIds.cend(),
        [](const int32_t &accountId) { return accountId >= 0; });
    if (iter != osAccountIds.end()) {
        return *iter;
    }
    WS_HILOGE("GetCurrentAccountId failed, no osAccountIds now.");
    return -1;
}

bool WorkSchedUtils::IsIdActive(int32_t id)
{
    std::vector<int32_t> osAccountIds;
    ErrCode ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(osAccountIds);
    if (ret != ERR_OK) {
        WS_HILOGE("QueryActiveOsAccountIds failed.");
        return false;
    }

    if (osAccountIds.empty()) {
        WS_HILOGE("osAccountIds is empty, no accounts.");
        return false;
    }

    auto iter = std::find_if(osAccountIds.cbegin(), osAccountIds.cend(),
        [&id](const int32_t &accountId) { return accountId == id; });
    if (iter != osAccountIds.end()) {
        return true;
    }
    WS_HILOGD("IsIdActive failed, osAccountIds now.");
    return false;
}

int32_t WorkSchedUtils::GetUserIdByUid(int32_t uid)
{
    if (uid <= INVALID_DATA) {
        WS_HILOGE("uid is illegal: %{public}d", uid);
        return INVALID_DATA;
    }
    const int32_t baseUserRange = 200000;
    return uid / baseUserRange;
}

bool WorkSchedUtils::ConvertFullPath(const std::string& partialPath, std::string& fullPath)
{
    if (partialPath.empty() || partialPath.length() >= PATH_MAX) {
        return false;
    }
    char tmpPath[PATH_MAX] = {0};
    if (realpath(partialPath.c_str(), tmpPath) == nullptr) {
        return false;
    }
    fullPath = tmpPath;
    return true;
}

bool WorkSchedUtils::IsSystemApp()
{
    uint64_t fullTokenId = IPCSkeleton::GetCallingFullTokenID();
    return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);
}

uint64_t WorkSchedUtils::GetCurrentTimeMs()
{
    using namespace std;
    auto now = chrono::system_clock::now();
    chrono::milliseconds currentTimeMs = chrono::duration_cast<chrono::milliseconds>(now.time_since_epoch());
    return currentTimeMs.count();
}

bool WorkSchedUtils::CheckExtensionInfos(const string &bundleName, const string &abilityName, int32_t uid)
{
    if (bundleName.empty() || abilityName.empty()) {
        return false;
    }

    sptr<ISystemAbilityManager> systemAbilityManager =
        SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (!systemAbilityManager) {
        WS_HILOGE("fail to get system ability mgr.");
        return false;
    }
    sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
    if (!remoteObject) {
        WS_HILOGE("fail to get bundle manager proxy.");
        return false;
    }
    sptr<IBundleMgr> bundleMgr = iface_cast<IBundleMgr>(remoteObject);
    BundleInfo bundleInfo;
    if (bundleMgr->GetBundleInfo(bundleName,
        BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO,
        bundleInfo, uid / UID_TRANSFORM_DIVISOR)) {
        auto findIter = std::find_if(bundleInfo.extensionInfos.begin(), bundleInfo.extensionInfos.end(),
            [&](const auto &info) {
                WS_HILOGD("%{public}s %{public}s %{public}d", info.bundleName.c_str(), info.name.c_str(), info.type);
                return info.bundleName == bundleName &&
                    info.name == abilityName &&
                    info.type == ExtensionAbilityType::WORK_SCHEDULER;
            });
        if (findIter == bundleInfo.extensionInfos.end()) {
            WS_HILOGE("extension info is error");
            return false;
        }
    }
    return true;
}

bool WorkSchedUtils::IsUserMode()
{
    bool secureMode = OHOS::system::GetBoolParameter("const.security.developermode.state", false);
    bool debugable = OHOS::system::GetIntParameter("const.debuggable", 0) == 1;
    return secureMode && !debugable;
}
} // namespace WorkScheduler
} // namespace OHOS